/**
 * Created by Administrator on 2017/1/17.
 */

var COLOR_CARD_NUM = 9;              // 每种花色有多少张牌
var COLOR_ZI_NUM = 7;                // 字牌有多少张牌

var Color = {    // 花色
    'TONG': 1,  // 筒
    'TIAO': 2,  // 条
    'WAN': 3,   // 万

    'ZI': 0,     // 字牌,1-7 东南西北 中发白
    'HUA': 4,    // 花牌
}



var ColorCardNum = {};
ColorCardNum[Color.TONG] = {point: COLOR_CARD_NUM, num:4};
ColorCardNum[Color.TIAO] = {point: COLOR_CARD_NUM, num:4};
ColorCardNum[Color.WAN] = {point: COLOR_CARD_NUM, num:4};
ColorCardNum[Color.ZI] = {point: COLOR_ZI_NUM, num:4};
ColorCardNum[Color.HUA] = {point: 8, num:1};

var ZI = {
    'DF': 1,    // 东
    'NF': 2,    // 南
    'XF': 3,    // 西
    'BF': 4,    // 北
    'HZ': 5,    // 中
    'FC': 6,    // 發
    'BB': 7     // 白
}

var Pattern = { // 基础牌型
    'NONE': 0,                // 不是可胡的牌型
    'NORMAL': 1,              // 平胡
    'PAIR': 2,                // 大对
    'PAIR7': 3,               // 七对
    'SINGLE': 4,              // 单调
}

var Gang = {
    'BA': 1,        // 巴杠
    'AN': 2,        // 暗杠
    'DIAN': 3,      // 点杠
    'ANS': 4,       // 暗杠（不是杠刚摸上的牌）
}

var Result = {
    DRAW: 0,        // 平局
    DH: 1,          // 点胡
    ZM: 2           // 自摸
}

var Task = {
    "HU": 1,         // 胡牌
    "GANG": 2,      // 杠牌
    "PENG": 3,      // 碰牌
    "CHI": 4,       // 吃牌

    "TING": 5,      // 听牌
    "CUSTOM": 8,   // 自定义

    "MOPAI": 9,     // 摸牌

    /* 虚拟任务 */
    "PASS": 11,     // 全过
    "PLAY": 12,     // 出牌
}

var ScoreRule = {
    'DH': Result.DH,         // 点胡/点炮
    'ZM': Result.ZM,         // 自摸加分

    'YPDX': 20,               // 一炮多响
    'LZ': 30,                 // 连庄
    'GANG': 40,               // 根

    // 特殊规则
    'GSH': 101,               // 杠上花   ，作用于胡牌玩家
    'GSP': 102,               // 杠上炮   ，作用于点炮玩家
    'QG': 103,                // 抢杠     ，作用于杠牌玩家
    'BT': 104,                // 报听     ，作用于胡牌玩家
    'TH': 105,                // 天胡     ，作用于胡牌玩家
    'DIHU': 107,              // 地胡     ，作用于胡牌玩家
    'TT': 108,                // 天听     ，作用于胡牌玩家
}

var SelectColorStatus = {
    'NONE': 0,
    'FINISHED': 1,
}

/**
 * 根据花色和点数计算牌值
 * @param color
 * @param point
 * @returns {*}
 */
function getValue(color, point) {
    return color*10 + point;
}

/**
 * 从牌值计算点数
 * @param value
 * @returns {number}
 */
function getPoint(value) {
    return value % 10;
}

/**
 * 从牌值计算花色
 * @param value
 * @returns {number}
 */
function getColor(value) {
    return Math.floor(value/10);
}


var Value = {};
Value.TONG1 = getValue(Color.TONG, 1);
Value.TONG9 = getValue(Color.TONG, 9);
Value.TIAO1 = getValue(Color.TIAO, 1);
Value.TIAO9 = getValue(Color.TIAO, 9);
Value.WAN1 = getValue(Color.WAN, 1);
Value.WAN9 = getValue(Color.WAN, 9);

/**
 * 是否是基础花色
 * @param color
 * @returns {boolean}
 */
function isBasicColor(color) {
    return color == Color.TONG || color == Color.TIAO || color == Color.WAN;
}

function buildFromArray(cardsArray) {
    var cards = {};
    cardsArray.forEach(function(card) {
        ExObject.addNumber(cards, card, 1);
    });
    return cards;
}

function isSameCards(cards1, cards2) {
    var keys1 = Object.keys(cards1);
    var keys2 = Object.keys(cards2);

    if (keys1.length != keys2.length) {
        return false;
    }

    var isSame = true;
    for (var i = 0, l  = keys1.length; i < l; ++i) {
        if (cards1[keys1[i]] != cards2[keys1[i]]) {
            isSame = false; break;
        }
    }

    return isSame;
}

/**
 * 计算牌组中牌的张数
 * @param cards
 * @returns {*}
 */
function sumCardsNum(cards) {
    return ExObject.sumValue(cards);
}

function existCard(cards, card) {
    return cards[card] > 0;
}

/**
 * 判断牌级中是否有指定花色的牌
 * @param cards
 * @param color
 * @returns {boolean}
 */
function existColor(cards, color) {
    var exist = false;
    ExObject.each(cards, function(card, num) {
        if (getColor(card) == color) {
            exist = true; return false;
        }
    })
    return exist;
}

function delCard(cards, card, delNum) {
    var num = cards[card] || 0;
    delNum = delNum || 1;

    if (num < delNum) {
        return false;
    } else if (num == delNum) {
        delete cards[card];
    } else {
        cards[card] = num - delNum;
    }
    return true;
}

function addCard(cards, card, num) {
    ExObject.addNumber(cards, card, num);
}

/**
 * 从牌组中获取指定花色的子牌组
 * @param cards
 * @returns {}
 */
function getColorCards(cards, color) {
    var colorCards = {};
    for (var card = this.getValue(color, 1), max = card + ColorCardNum[color].point; card < max; ++card) {
        var num = cards[card];
        if (num) {
            colorCards[card] = num;
        }
    }
    return colorCards;
}

function getSectionCards(cards, minCard, maxCard) {
    var sectionCards = {};
    for (var card = minCard; card <= maxCard; ++card) {
        var num = cards[card];
        if (num) {
            sectionCards[card] = num;
        }
    }
    return sectionCards;
}

module.exports = {
    COLOR_CARD_NUM: COLOR_CARD_NUM,
    COLOR_ZI_NUM: COLOR_ZI_NUM,

    Color: Color,
    ColorCardNum: ColorCardNum,
    Pattern: Pattern,
    Gang: Gang,
    Result: Result,
    Task: Task,
    ScoreRule: ScoreRule,
    SelectColorStatus: SelectColorStatus,

    ZI: ZI,
    Value: Value,

    getValue: getValue,
    getPoint: getPoint,
    getColor: getColor,
    isBasicColor: isBasicColor,
    buildFromArray: buildFromArray,
    isSameCards: isSameCards,
    sumCardsNum: sumCardsNum,
    existCard: existCard,
    existColor: existColor,
    delCard: delCard,
    addCard: addCard,
    getColorCards: getColorCards,
    getSectionCards: getSectionCards,


    checkHuColorCards: function(minCard, maxCard, colorCards) {
        var colorCardsNum = sumCardsNum(colorCards);
        if (colorCardsNum == 0) {
            return true;
        }

        var context = {result: false};
        var modNum = colorCardsNum % 3;
        if (modNum == 0) {
            this.checkHu3X(minCard, maxCard, colorCards, context);
        } else if (modNum == 2) {
            this.checkHu3X2(minCard, maxCard, colorCards, context);
        }

        return context.result
    },

    checkHu3X: function(minCard, maxCard, cards, context) {
        if (sumCardsNum(cards) < 1) {
            context.result = true;
            return;
        }

        for (var i = minCard; i <= maxCard; ++i) {
            var num = cards[i];
            if (!num) {
                continue;
            }

            var num2 = cards[i + 1];
            var num3 = cards[i + 2];

            if (num == 3) {
                if (num2 >= 3 && num3 >= 3) {
                    var newCards = clone(cards);
                    newCards[i] = 0;
                    newCards[i + 1] = num2 - 3;
                    newCards[i + 2] = num3 - 3;
                    this.checkHu3X(minCard, maxCard, newCards, context);
                }

                cards[i] = 0;
                this.checkHu3X(minCard, maxCard, cards, context);
            } else {
                if (num2 && num3) {
                    cards[i] = num - 1;
                    cards[i + 1] = num2 - 1;
                    cards[i + 2] = num3 - 1;
                    this.checkHu3X(minCard, maxCard, cards, context);
                }
            }
            break;
        }
    },

    checkHu3X2: function(minCard, maxCard, cards, context) {
        for (var i = minCard; i <= maxCard; ++i) {
            var num = cards[i];
            if (num >= 2) {
                var newCards = clone(cards);
                newCards[i] = num - 2;
                this.checkHu3X(minCard, maxCard, newCards, context);
                if (context.result) break;
            }
        }
    },

    checkPairHuColorCards: function(cards) {
        var num3 = 0;
        var num2 = 0;
        var numOther = 0;

        ExObject.each(cards, function(c, n) {
            if (n == 2) {
                num2++;
            } else if (n == 3) {
                num3++;
            } else {
                numOther++;
            }
        });

        return (numOther == 0) && (num2 <= 1);
    },

    //宝牌字牌拆牌

    checkBaoPairColorCards: function(cards, context) {
        var colorCardsNum = this.sumCardsNum(cards);
        for(var bn = 0; context.curbaocard >= bn; bn++){
            var curbn = bn;
            var curmodNum = (colorCardsNum + curbn) % 3;
            if(curmodNum == 0){
                context.result = this.checkBaoPairHuColorCards(cards, curbn, context.zi);
                if (context.result) {
                    context.curbaocard -= curbn;
                    break;
                }
            } else if(curmodNum == 2 && !context.hu3x2){
                for (var i = 1; i <= 7; ++i) {
                    var num = cards[i];
                    curbn = context.curbaocard;
                    if (num >= 2) {
                        var newCards = clone(cards);
                        newCards[i] = num - 2;
                        context.result = this.checkBaoPairHuColorCards(newCards, curbn, context.zi);
                        if (context.result) {
                            break;
                        }
                    } else if(num == 1 && context.curbaocard) {
                        var newCards = clone(cards);
                        newCards[i] = 0;
                        curbn--;
                        context.result = this.checkBaoPairHuColorCards(newCards, curbn, context.zi);
                        if (context.result) {
                            break;
                        }
                    }
                }
                if (context.result) {
                    context.curbaocard -= curbn;
                    context.hu3x2 = true;
                    break;
                }
            }
            if(context.result) {
                break;
            }
        }
    },
    //宝牌字牌拆胡牌

    checkBaoPairHuColorCards: function(cards, baocard, zi) {
        var num4 = 0;
        var num3 = 0;
        var num2 = 0;
        var numOther = 0;
        var colorCardsNum = this.sumCardsNum(cards);
        if (colorCardsNum < 1) {
            return true;
        }
        var newcard = baocard;
        ExObject.each(cards, function(c, n) {
            if(n == 1){
                if(newcard) {
                    newcard--;
                    num2++;
                }else{
                    numOther++;
                }
            }else if (n == 2) {
                if(newcard) {
                    newcard--;
                    num3++;
                }else{
                    num2++;
                }
            } else if (n == 3) {
                num3++;
            } else if (n == 0) {
            }else {
                numOther++;
            }
        });
        if((numOther == 0) && (num2 <= 1)) {
            return true;
        }
        if(zi){
            var context = {result: false};
            this.checkZiCard(cards, context, baocard);
            return context.result;
        }else {
            return false;
        }

    },
    checkBaoHu3X: function(minCard, maxCard, cards, context, baocard) {
        var colorCardsNum = this.sumCardsNum(cards);
        if (colorCardsNum < 1) {
            context.result = true;
            return;
        }
        for (var i = minCard; i <= maxCard; ++i) {
            var num = cards[i];
            if (!num) {
                continue;
            }
            var num2 = cards[i + 1];
            var num3 = cards[i + 2];
            if (num == 3) {
                if (num2 > 0 && num3 > 0) {
                    var iTmp = 0;
                    if (num2 < 3) {
                        iTmp += 3 - num2;
                    }
                    if (num3 < 3) {
                        iTmp += 3 - num3;
                    }
                    if (iTmp <= baocard) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[i] = 0;
                        if (num2 >= 3) {
                            newCards[i + 1] = num2 - 3;
                        } else{
                            newbaocard -= 3 - newCards[i + 1];
                            newCards[i + 1] = 0;
                        }
                        if (num3 >= 3) {
                            newCards[i + 2] = num3 - 3;
                        } else {
                            newbaocard -= 3 - newCards[i + 2];
                            newCards[i + 2] = 0;
                        }
                        this.checkBaoHu3X(minCard, maxCard, newCards, context, newbaocard);
                    }
                }
                cards[i] = 0;
                this.checkBaoHu3X(minCard, maxCard, cards, context, baocard);
            } else if(num == 2){
                if (num2 > 0 && num3 > 0){
                    var iTmp = 0;
                    if (num2 < 2) {
                        iTmp += 2 - num2;
                    }
                    if (num3 < 2) {
                        iTmp += 2 - num3;
                    }
                    if (iTmp <= baocard) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[i] = 0;
                        if (num2 >= 2) {
                            newCards[i + 1] = num2 - 2;
                        } else{
                            newbaocard -= 2 - newCards[i + 1];
                            newCards[i + 1] = 0;
                        }
                        if (num3 >= 2) {
                            newCards[i + 2] = num3 - 2;
                        } else {
                            newbaocard -= 2 - newCards[i + 2];
                            newCards[i + 2] = 0;
                        }
                        this.checkBaoHu3X(minCard, maxCard, newCards, context, newbaocard);
                    }
                }
                if(baocard){
                    cards[i] = 0;
                    baocard--;
                    this.checkBaoHu3X(minCard, maxCard, cards, context, baocard);
                }
                if (((num2 || num3) && baocard) || (num2 && num3)) {
                    var newCards = clone(cards);
                    var newbaocard = baocard;
                    newCards[i] = num - 1;
                    if(num2) {
                        newCards[i + 1] = num2 - 1;
                    }else{
                        newbaocard--;
                    }
                    if(num3){
                        newCards[i + 2] = num3 - 1;
                    }
                    else{
                        newbaocard--;
                    }
                    this.checkBaoHu3X(minCard, maxCard, newCards, context, newbaocard);
                }
                if(num == 1 && baocard >= 2){
                    cards[i] = 0;
                    baocard -= 2;
                    this.checkBaoHu3X(minCard, maxCard, cards, context, baocard);
                }
            } else {
                if (((num2 || num3) && baocard) || (num2 && num3)) {
                    var newCards = clone(cards);
                    var newbaocard = baocard;
                    newCards[i] = num - 1;
                    if(num2) {
                        newCards[i + 1] = num2 - 1;
                    }else{
                        newbaocard--;
                    }
                    if(num3){
                        newCards[i + 2] = num3 - 1;
                    }
                    else{
                        newbaocard--;
                    }
                    this.checkBaoHu3X(minCard, maxCard, newCards, context, newbaocard);
                }
                if(num && baocard >= 2){
                    cards[i] -= 1;
                    baocard -= 2;
                    this.checkBaoHu3X(minCard, maxCard, cards, context, baocard);
                }
            }
            break;
        }
    },
    checkBaoHu3X2: function(minCard, maxCard, cards, context, baocard) {
        for (var i = minCard; i <= maxCard; ++i) {
            var num = cards[i];

            if (num >= 2) {
                var newCards = clone(cards);
                newCards[i] = num - 2;

                var newBaocard = baocard;
                this.checkBaoHu3X(minCard, maxCard, newCards, context, newBaocard);
                if (context.result){
                    context.result = true;
                    break;
                }
            } else if(num == 1 && baocard) {
                var newCards = clone(cards);
                newCards[i] = 0;
                var newBaocard = baocard;
                newBaocard--;
                this.checkBaoHu3X(minCard, maxCard, newCards, context, newBaocard);
                if (context.result){
                    context.result = true;
                    break;
                }
            }
        }
    },
    //宝牌基础花色拆牌
    checkBaoColorCards: function(minCard, maxCard, cards, context){
        var colorCardsNum = this.sumCardsNum(cards);
        for(var bn = 0; bn <= context.curbaocard; bn++){
            var curbn = bn;
            var curmodNum = (colorCardsNum + curbn) % 3;
            if(curmodNum == 0){
                this.checkBaoHu3X(minCard, maxCard, cards, context, curbn);
                if (context.result) {
                    context.curbaocard -= curbn;
                    break;
                }
            } else if(curmodNum == 2 && !context.hu3x2){
                this.checkBaoHu3X2(minCard, maxCard, cards, context, curbn);
                if (context.result) {
                    context.curbaocard -= curbn;
                    context.hu3x2 = true;
                    break;
                }
            }
        }
    },
    /**
     * 是否可以胡13幺
     * @param cards
     */
    checkHuOne13: function(cards) {
        var cardArr = Object.keys(cards);
        if (cardArr.length != 13) {
            return false;
        }

        return (cards[Value.TONG1] > 0) &&
            (cards[Value.TONG9] > 0) &&
            (cards[Value.TIAO1] > 0) &&
            (cards[Value.TIAO9] > 0) &&
            (cards[Value.WAN1] > 0) &&
            (cards[Value.WAN9] > 0) &&
            (cards[ZI.DF] > 0) &&
            (cards[ZI.NF] > 0) &&
            (cards[ZI.XF] > 0) &&
            (cards[ZI.BF] > 0) &&
            (cards[ZI.HZ] > 0) &&
            (cards[ZI.FC] > 0) &&
            (cards[ZI.BB] > 0);
    },

    checkHuPair7: function(cards) {
        var num = 0;
        ExObject.each(cards, function(c, n) {
            if (n == 2) {
                num += 1;
            } else if (n == 4) {
                num += 2;
            }
        });

        return (num == 7);
    },
    /*checkOneLong: function(colors, cards, baocard, BaoCard){
        var room = this.getRoom();

        if(this.sumCardsNum(cards) < 9){
            return false;
        }

        var curBaocard = baocard;
        //遍历每个花色
        for (var i = 0, l = colors.length; i < l; ++i) {
            var color = colors[i];
            var colorCards = this.getColorCards(cards, color);
            //如果颜色是宝牌颜色，去除宝牌再检测
            if (color == this.getColor(BaoCard)) {
                colorCards[BaoCard] = 0;
            }
            var colorCardsNum = this.sumCardsNum(colorCards);
            if (colorCardsNum < 7) {
                continue;
            }
            var long = false;

            for(var bn = 0; bn <= baocard; bn++) {
                var curbn = bn;
                if (colorCardsNum + curbn >= 9) {
                    long = true;
                    for (var j = this.getValue(color, 1), k = this.getValue(color, this.COLOR_CARD_NUM); j <= k; j++) {
                        if (!colorCards[j]) {
                            if (curbn) {
                                curbn--;
                            } else {
                                long = false;
                                break;
                            }
                        }
                    }
                    if (long) {
                        for (var ii = this.getValue(color, 1), ll = this.getValue(color, this.COLOR_CARD_NUM); ii <= ll; ii++) {
                            if (colorCards[ii]) {
                                cards[ii] -= 1;
                            }
                        }
                        curBaocard -= bn;
                        if(bn){
                            this._suhu = false;
                        }
                        break;
                    }

                }
            }
        }
        if(long){
            var hu3x2 = false;
            for (var i = 0, l = colors.length; i < l; ++i) {
                var color = colors[i];
                var colorCards = this.getColorCards(cards, color);
                //如果颜色是宝牌颜色，去除宝牌再检测
                if (color == this.getColor(room.baoCard)) {
                    colorCards[room.baoCard] = 0;
                }
                var colorCardsNum = this.sumCardsNum(colorCards);
                if (colorCardsNum < 1) {
                    continue;
                }
                var context = {
                    result: false,
                    hu3x2:hu3x2,
                    curbaocard:curBaocard
                };
                this.checkBaoColorCards(this.getValue(color, 1), this.getValue(color, this.COLOR_CARD_NUM), colorCards, context);
                if(!context.result){
                    return false;
                }
                hu3x2 = context.hu3x2;
                curBaocard = context.curbaocard;
            }
        }else {
            return false;
        }
        return true;

    },*/
    splitColorCards: function(minCard, maxCard, cards) {
        var results = [];

        var colorCardsNum = sumCardsNum(cards);
        if (colorCardsNum == 0) {
            return results;
        }
        var modNum = colorCardsNum % 3;
        if (modNum == 0) {
            var context = {cards:clone(cards), items:[]};
            this.split3X(minCard, maxCard, context, results);
        } else {
            this.split3X2(minCard, maxCard, cards, results);
        }
        return results;
    },

    /**
     *
     * @param context {cards:{}, items:[]}
     */
    split3X: function(minCard, maxCard, context, results) {
        var cards = context.cards;
        if (sumCardsNum(cards) < 1) {
            results.push(context.items);
            return;
        }

        for (var i = minCard; i <= maxCard; ++i) {
            var num = cards[i];
            if (!num) {
                continue;
            }

            var num2 = cards[i + 1];
            var num3 = cards[i + 2];

            if (num == 3) {
                if (num2 >= 3 && num3 >= 3) {
                    var newContext = clone(context);
                    newContext.cards[i] = 0;
                    newContext.cards[i + 1] = num2 - 3;
                    newContext.cards[i + 2] = num3 - 3;
                    newContext.items.push([i, i+1, i+2]);
                    newContext.items.push([i, i+1, i+2]);
                    newContext.items.push([i, i+1, i+2]);
                    this.split3X(minCard, maxCard, newContext, results);
                }

                cards[i] = 0;
                context.items.push([i, i, i]);
                this.split3X(minCard, maxCard, context, results);
            } else {
                if (num2 && num3) {
                    cards[i] = num - 1;
                    cards[i + 1] = num2 - 1;
                    cards[i + 2] = num3 - 1;
                    context.items.push([i, i+1, i+2]);
                    this.split3X(minCard, maxCard, context, results);
                }
            }
            break;
        }
    },
    checkZiCard:function(cards, context, baocard) {
        var room = {'baoCard': 0};
        room.baoCard = 0;
        var colorCardsNum = sumCardsNum(cards);
        if (colorCardsNum < 1) {
            context.result = true;
            return;
        }
        var color = Color.ZI;

        for (var p = 1; p <= 7; ++p) {
            var num = cards[p];
            if (!num) {
                continue;
            }
            var point = p;
            if (point > ZI.BF) {
                var num2 = 0;
                var num3 = 0;
                var point2 = 0;
                var point3 = 0;
                for (var i = ZI.HZ; i <= ZI.BB; i++) {
                    if (i == point) {
                        continue;
                    }
                    var tmpCard = getValue(color, i);
                    /*if (tmpCard == room.baoCard) {
                        continue
                    }*/
                    num2 = cards[tmpCard];
                    if(num2){
                        num2 = 0;
                    }
                    point2 = i;
                }
                for (var i = ZI.HZ; i <= ZI.BB; i++) {
                    if (i == point) {
                        continue;
                    }
                    var tmpCard = getValue(color, i);
                    /*if (tmpCard == room.baoCard) {
                        continue
                    }*/
                    if (i == point2) {
                        continue;
                    }
                    num3 = cards[tmpCard];
                    if(num3){
                        num3 = 0;
                    }
                    point3 = i;
                }
                if (num == 3) {
                    if (num2 > 0 && num3 > 0) {
                        var iTmp = 0;
                        if (num2 < 3) {
                            iTmp += 3 - num2;
                        }
                        if (num3 < 3) {
                            iTmp += 3 - num3;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 3) {
                                newCards[point2] = num2 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num3 >= 3) {
                                newCards[point3] = num3 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    cards[point] = 0;
                    this.checkZiCard(cards, context, baocard);
                } else if (num == 2) {
                    if (num2 > 0 && num3 > 0) {
                        var iTmp = 0;
                        if (num2 < 2) {
                            iTmp += 2 - num2;
                        }
                        if (num3 < 2) {
                            iTmp += 2 - num3;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 2) {
                                newCards[point2] = num2 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num3 >= 2) {
                                newCards[point3] = num3 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    cards[point] = 0;
                    baocard--;
                    this.checkZiCard(cards, context, baocard);
                } else {
                    if (((num2 || num3) && baocard) || (num2 && num3)) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[point] = num - 1;
                        if (num2) {
                            newCards[point2] = num2 - 1;
                        } else {
                            newbaocard--;
                        }
                        if (num3) {
                            newCards[point3] = num3 - 1;
                        }
                        else {
                            newbaocard--;
                        }
                        this.checkZiCard(newCards, context, newbaocard);
                    }
                    if (num == 1 && baocard >= 2) {
                        cards[point] = 0;
                        baocard -= 2;
                        this.checkZiCard(cards, context, baocard);
                    }
                }
                break;
            } else {
                var num2 = 0;
                var num3 = 0;
                var num4 = 0;
                var point2 = 0;
                var point3 = 0;
                var point4 = 0;
                for (var i = ZI.DF; i <= ZI.BF; i++) {
                    if (i == point) {
                        continue;
                    }
                    var tmpCard = getValue(color, i);
                    if (tmpCard == room.baoCard) {
                        continue
                    }
                    num2 = cards[tmpCard];
                    point2 = i;
                }
                for (var i = ZI.DF; i <= ZI.BF; i++) {
                    if (i == point) {
                        continue;
                    }
                    var tmpCard = getValue(color, i);
                    if (tmpCard == room.baoCard) {
                        continue
                    }
                    if (i == point2) {
                        continue;
                    }
                    num3 = cards[tmpCard];
                    point3 = i;
                }
                for (var i = ZI.DF; i <= ZI.BF; i++) {
                    if (i == point) {
                        continue;
                    }
                    var tmpCard = getValue(color, i);
                    if (tmpCard == room.baoCard) {
                        continue
                    }
                    if (i == point2) {
                        continue;
                    }
                    if (i == point3) {
                        continue;
                    }
                    num4 = cards[tmpCard];
                    point4 = i;
                }
                if (num == 3) {
                    if (num2 > 0 && num3 > 0 && !context.result) {
                        var iTmp = 0;
                        if (num2 < 3) {
                            iTmp += 3 - num2;
                        }
                        if (num3 < 3) {
                            iTmp += 3 - num3;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 3) {
                                newCards[point2] = num2 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num3 >= 3) {
                                newCards[point3] = num3 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    if(num2 > 0 && num4 > 0 && !context.result) {
                        var iTmp = 0;
                        if (num2 < 3) {
                            iTmp += 3 - num2;
                        }
                        if (num3 < 3) {
                            iTmp += 3 - num4;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 3) {
                                newCards[point2] = num2 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num4 >= 3) {
                                newCards[point4] = num4 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point4];
                                newCards[point4] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    if(num3 > 0 && num4 > 0 && !context.result) {
                        var iTmp = 0;
                        if (num3 < 3) {
                            iTmp += 3 - num3;
                        }
                        if (num4 < 3) {
                            iTmp += 3 - num4;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num3 >= 3) {
                                newCards[point3] = num3 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            if (num4 >= 3) {
                                newCards[point4] = num4 - 3;
                            } else {
                                newbaocard -= 3 - newCards[point4];
                                newCards[point4] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    cards[point] = 0;
                    this.checkZiCard(cards, context, baocard);
                } else if (num == 2) {
                    if (num2 > 0 && num3 > 0) {
                        var iTmp = 0;
                        if (num2 < 2) {
                            iTmp += 2 - num2;
                        }
                        if (num3 < 2) {
                            iTmp += 2 - num3;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 2) {
                                newCards[point2] = num2 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num3 >= 2) {
                                newCards[point3] = num3 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    if(num2 > 0 && num4 > 0 && !context.result) {
                        var iTmp = 0;
                        if (num2 < 2) {
                            iTmp += 2 - num2;
                        }
                        if (num3 < 2) {
                            iTmp += 2 - num4;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num2 >= 2) {
                                newCards[point2] = num2 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point2];
                                newCards[point2] = 0;
                            }
                            if (num4 >= 2) {
                                newCards[point4] = num4 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point4];
                                newCards[point4] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    if(num3 > 0 && num4 > 0 && !context.result) {
                        var iTmp = 0;
                        if (num3 < 2) {
                            iTmp += 2 - num3;
                        }
                        if (num4 < 2) {
                            iTmp += 2 - num4;
                        }
                        if (iTmp <= baocard) {
                            var newCards = clone(cards);
                            var newbaocard = baocard;
                            newCards[point] = 0;
                            if (num3 >= 2) {
                                newCards[point3] = num3 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point3];
                                newCards[point3] = 0;
                            }
                            if (num4 >= 2) {
                                newCards[point4] = num4 - 2;
                            } else {
                                newbaocard -= 2 - newCards[point4];
                                newCards[point4] = 0;
                            }
                            this.checkZiCard(newCards, context, newbaocard);
                        }
                    }
                    cards[point] = 0;
                    baocard--;
                    this.checkZiCard(cards, context, baocard);
                } else {
                    if (((num2 || num3) && baocard) || (num2 && num3)) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[point] = num - 1;
                        if (num2) {
                            newCards[point2] = num2 - 1;
                        } else {
                            newbaocard--;
                        }
                        if (num3) {
                            newCards[point3] = num3 - 1;
                        }
                        else {
                            newbaocard--;
                        }
                        this.checkZiCard(newCards, context, newbaocard);
                    }
                    if ((((num2 || num4) && baocard) || (num2 && num4)) && !context.result) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[point] = num - 1;
                        if (num2) {
                            newCards[point2] = num2 - 1;
                        } else {
                            newbaocard--;
                        }
                        if (num4) {
                            newCards[point4] = num4 - 1;
                        }
                        else {
                            newbaocard--;
                        }
                        this.checkZiCard(newCards, context, newbaocard);
                    }
                    if ((((num3 || num4) && baocard) || (num3 && num4)) && !context.result) {
                        var newCards = clone(cards);
                        var newbaocard = baocard;
                        newCards[point] = num - 1;
                        if (num3) {
                            newCards[point3] = num3 - 1;
                        } else {
                            newbaocard--;
                        }
                        if (num4) {
                            newCards[point4] = num4 - 1;
                        }
                        else {
                            newbaocard--;
                        }
                        this.checkZiCard(newCards, context, newbaocard);
                    }
                    if (num == 1 && baocard >= 2) {
                        cards[point] = 0;
                        baocard -= 2;
                        this.checkZiCard(cards, context, baocard);
                    }
                }
                break;
            }
        }
    },
    split3X2: function(minCard, maxCard, cards, results) {
        for (var card = minCard; card <= maxCard; ++card) {
            var num = cards[card];
            if (num >= 2) {
                var rIdx = results.length;

                var context = {cards:clone(cards), items:[]};
                delCard(context.cards, card, 2);
                this.split3X(minCard, maxCard, context, results);

                for (var i = rIdx, l = results.length; i < l; ++i) {
                    results[i].push([card, card]);
                }
            }
        }
    },
}